#include <sys/system.h>
#include <sys/task.h>

#define PT_MSG_QUEUE_SIZE	100
#define PT_TIME_MSG_QUEUE_SIZE	50

#define PT_MSG_FLAG_UNUSED	0x00
#define PT_MSG_FLAG_USED	0x01
#define PT_MSG_FLAG_DROPED	0x02

typedef struct {
	pt_uint8_t	flag;
	pt_event_t message;
} pt_msg_queue_t;

typedef struct {
	pt_uint8_t	flag;
	pt_event_t message;
	pt_time_t	time;
} pt_time_msg_queue_t;

static pt_event_t _current_message;

static pt_task_id_t	_current_task_id;
static pt_uint8_t	_time_task_flag;
static pt_msg_queue_t	_msg_queue[PT_MSG_QUEUE_SIZE];
static pt_uint16_t	_msg_front;
static pt_uint16_t	_msg_end;
static pt_time_msg_queue_t	_time_msg_queue[PT_TIME_MSG_QUEUE_SIZE];

void pt_message_system_init(void)
{
	pt_memset(_msg_queue, 0, sizeof(_msg_queue));
	pt_memset(_time_msg_queue, 0, sizeof(_msg_queue));

	_msg_front = 0;
	_msg_end = 0;

	_time_task_flag = 0;
	_current_task_id = 0;
}

pt_err_t pt_post_message(pt_task_id_t dest_task_id, pt_event_id_t msg_id, 
							pt_wparam_t wparam, pt_lparam_t lparam)
{
	if ((_msg_end + 1) % PT_MSG_QUEUE_SIZE == _msg_front) {
		return PT_ERROR;
	}

	_msg_queue[_msg_end].flag = PT_MSG_FLAG_USED;
	_msg_queue[_msg_end].message.destId = dest_task_id;
	_msg_queue[_msg_end].message.srcId = _current_task_id;
	_msg_queue[_msg_end].message.type = msg_id;
	_msg_queue[_msg_end].message.wparam = wparam;
	_msg_queue[_msg_end].message.lparam = lparam;

	_msg_end = (_msg_end + 1) % PT_MSG_QUEUE_SIZE;
	return PT_EOK;
}

pt_err_t pt_post_time_message(pt_task_id_t dest_task_id, pt_event_id_t msg_id, 
							pt_wparam_t wparam, pt_lparam_t lparam, pt_time_t time)
{
	pt_uint16_t index;

	for (index = 0; index < PT_TIME_MSG_QUEUE_SIZE; index++) {
		if (_time_msg_queue[index].flag != PT_MSG_FLAG_USED) {
			_time_msg_queue[index].flag = PT_MSG_FLAG_USED;
			_time_msg_queue[index].time = time;
			_time_msg_queue[_msg_end].message.destId = dest_task_id;
			_time_msg_queue[_msg_end].message.srcId = _current_task_id;
			_time_msg_queue[_msg_end].message.type = msg_id;
			_time_msg_queue[_msg_end].message.wparam = wparam;
			_time_msg_queue[_msg_end].message.lparam = lparam;
			break;
		}
	}

	return PT_ERROR;
}

pt_err_t pt_send_message(pt_task_id_t dest_task_id, pt_event_id_t msg_id, 
							pt_wparam_t wparam, pt_lparam_t lparam)
{
	if (dest_task_id < PT_TSK_ID_MAX) {		
		_current_message.destId = dest_task_id;
		_current_message.srcId = _current_task_id;
		_current_message.type = msg_id;
		_current_message.wparam = wparam;
		_current_message.lparam = lparam;
		pt_task_table[dest_task_id](&_current_message);
		return PT_EOK;
	}

	return PT_ERROR;
}

pt_err_t pt_peek_message(pt_event_t* message)
{
	while (_msg_front < _msg_end) {
		if (_msg_queue[_msg_front].flag == PT_MSG_FLAG_USED) {
			break;
		}
		_msg_front++;
	}

	if (_msg_front == _msg_end) {
		/* empty */
		return PT_ERROR;
	}

	message->destId = _msg_queue[_msg_front].message.destId;
	message->srcId = _msg_queue[_msg_front].message.srcId;
	message->type = _msg_queue[_msg_front].message.type;
	message->wparam = _msg_queue[_msg_front].message.wparam;
	message->lparam = _msg_queue[_msg_front].message.lparam;

	_msg_front = (_msg_front + 1) % PT_MSG_QUEUE_SIZE;
	return PT_EOK;
}

pt_err_t pt_translate_message(pt_event_t* message)
{
	return PT_EOK;
}

pt_err_t pt_dispatch_message(pt_event_t* message)
{
	if (message->destId < PT_TSK_ID_MAX) {
		if (pt_task_table[message->destId] != PT_NULL) {
			_current_message = *message;
			pt_task_table[message->destId](message);
		}
	}

	if( _time_task_flag == 1 ) {
		_time_task_flag = 0;
		//pt_exec_time_task();
	}

	return PT_EOK;
}

pt_err_t pt_delete_message_quick(pt_event_id_t msg_id)
{
	pt_uint16_t index;

	for (index = 0; index < PT_TIME_MSG_QUEUE_SIZE; index++) {
		if (_time_msg_queue[index].message.type == msg_id) {
			_time_msg_queue[index].flag = PT_MSG_FLAG_DROPED;
		}
	}

	for (index = 0; index < PT_MSG_QUEUE_SIZE; index++) {
		if (_msg_queue[index].message.type == msg_id) {
			_msg_queue[index].flag = PT_MSG_FLAG_DROPED;
		}
	}

	return PT_EOK;
}

pt_err_t pt_delete_message(pt_event_t* message)
{

	pt_uint16_t index;

	for (index = 0; index < PT_TIME_MSG_QUEUE_SIZE; index++) {
		if (pt_memcmp(message, &_time_msg_queue[index].message, sizeof(pt_event_t)) == 0) {
			_time_msg_queue[index].flag = PT_MSG_FLAG_DROPED;
		}
	}

	for (index = 0; index < PT_MSG_QUEUE_SIZE; index++) {
		if (pt_memcmp(message, &_msg_queue[index].message, sizeof(pt_event_t)) == 0) {
			_msg_queue[index].flag = PT_MSG_FLAG_DROPED;
		}
	}

	return PT_EOK;
}

void pt_tick_ISR(void)
{
	pt_uint16_t index;
	pt_event_t *message;

	for (index = 0; index < PT_TIME_MSG_QUEUE_SIZE; index++) {
		if ((_time_msg_queue[index].flag == PT_MSG_FLAG_USED) ) {
			if (_time_msg_queue[index].time < PT_MONITOR_TIMER_PERIOD) {
				if ((_msg_end + 1) % PT_MSG_QUEUE_SIZE == _msg_front) {
					return;
				}
				
				message = &_time_msg_queue[index].message;

				_msg_queue[_msg_end].flag = PT_MSG_FLAG_USED;
				_msg_queue[_msg_end].message.destId = message->destId;
				_msg_queue[_msg_end].message.srcId = message->srcId;
				_msg_queue[_msg_end].message.type = message->type;
				_msg_queue[_msg_end].message.wparam = message->wparam;
				_msg_queue[_msg_end].message.lparam = message->lparam;
				_msg_end++;

				_time_msg_queue[index].flag = PT_MSG_FLAG_UNUSED;				
			}
			else {
				_time_msg_queue[index].time -= PT_MONITOR_TIMER_PERIOD;
			}
		}		
	}

	//_time_task_flag = 1;
	pt_exec_time_task();
}